package com.gillion.grape.fros.core.data;

import com.gillion.grape.fros.ui.Platform;





/**
 * 数据类型节点.用来描述数据类型的名称和长度<p/>
 * 模型间数据类型转换<p/>
 * <p/>
 * | MODEL        | ORACLE      | JAVA       | FLEX    | Hibernate.hbm.xml		<p/>
 * |--------------+-------------+------------+---------+------------------------<p/>
 * | string       | varchar(n)  | String     | String  | java.lang.String		<p/>
 * | integer      | decimal(p)  | Long       | Number  | java.lang.Long  		<p/>
 * | boolean      | character(n)| Boolean    | Boolean | java.lang.Boolean 		<p/>
 * | decimal      | decimal(p,s)| BigDecimal | Number  | java.math.BigDecimal  	<p/>
 * | date         | timestamp   | Date       | Date    | java.util.Date     	<p/>
 * 
 * 注:<p/>
 *   1. 每添加一种数据类型,需要在DATATYPETABLE中添加一行,并在{@link DataType}中添加一个数据类型枚举.<p/>
 *   2. 每添加一种技术平台,需要在DATATYPETABLE中添加一列,并在{@link Platform}中添加一个数据类型枚举.<p/>
 *   3.	MODEL的类型大小写忽略.<p/>
 * @author meichenhui
 * @since 2011-9-17
 *
 */
public class TypeEntry {
	
	// 数据类型映射表
	public static final String[][] DATATYPETABLE = new String[][]{
		//MODEL		ERmaster			JAVA			FLEX		HIBERNATE_HBM		ORACLE		SQLSERVER
		{"string",	"varchar(n)",	"String",		"String",	"java.lang.String",		"VARCHAR2",		"varchar"},		// STRING
		{"integer",	"decimal(p)",	"Long",			"Number",	"java.lang.Long",		"Number",		"numeric(1,0)"},			// INT
		{"boolean",	"character(n)", "Boolean",		"Boolean",	"java.lang.Boolean",	"CHAR(1)",		"numeric(1,0)"},			// BOOLEAN
		{"decimal",	"decimal(p,s)",	"BigDecimal",	"Number",	"java.math.BigDecimal",	"Number",		"numeric"},			// DECIMAL
		{"date",	"timestamp",	"Date",			"Date",		"java.util.Date",		"Date",		     "datetime"},			// DATE
	};
	
	private DataType type; 				// 类型
	private Integer length = 1; 		// 长度.默认1
	private Platform platform; 			// 技术平台
	private Platform targetPlatform; 	// 目标平台
	private Integer decimal; 			// 小数位数
	private String lenExpression;		// 长度表达式

	public Integer getDecimal() {
		return decimal;
	}

	public void setDecimal(Integer decimal) {
		this.decimal = decimal;
	}

	public Platform getPlatform() {
		return platform;
	}

	public void setPlatform(Platform platform) {
		this.platform = platform;
	}

	public DataType getType() {
		return type;
	}

	public void setType(DataType type) {
		this.type = type;
	}

	public Integer getLength() {
		return length;
	}

	public String getLenExpression() {
		return lenExpression;
	}

	public void setLenExpression(String lenExpression) {
		this.lenExpression = lenExpression;
	}

	public Platform getTargetPlatform() {
		return targetPlatform;
	}

	public void setTargetPlatform(Platform targetPlatform) {
		this.targetPlatform = targetPlatform;
	}

	/**
	 * 数据长度默认为1,不允许为空
	 * @param length
	 *
	 * @author meichenhui
	 * @since 2011-9-17
	 *
	 */
	public void setLength(Integer length) {
		if (length == null){
			return;
		}
		this.length = length;
	}
	
	public String getDataTypeName(){
		String tableDesc = getDataTableDesc();
//		if (tableDesc.contains("(")){
//			return tableDesc.substring(0,tableDesc.lastIndexOf('('));
//		}
		return tableDesc;
	}
	
	public String getDataTableDesc(){
		return DATATYPETABLE[getType().getIndex()][getTargetPlatform().getIndex()];
	}
	
	public String toString(){
		StringBuilder lengthString = new StringBuilder(getDataTypeName());
		// 判断是否拼接长度
		if (getLength() == null){
			return lengthString.toString();
		}
		lengthString.append("{").append(getLength());
		
		if (getDecimal() != null){ // 判断是否拼接小数位
			lengthString.append(",").append(getDecimal());
		}
		lengthString.append("}");
		return lengthString.toString();
	}
	
//	public String toSQLString() {
//		StringBuilder lengthString = new StringBuilder(getDataTypeName());
//		StringBuilder sqlLengthExpression = new StringBuilder();
//
//		// 判断是否拼接长度
//		if (getLength() == null) {
//			return lengthString.toString();
//		}
//		sqlLengthExpression.append("(").append(getLength());
//
//		if (getDecimal() != null) { // 判断是否拼接小数位
//			sqlLengthExpression.append(",").append(getDecimal());
//		}
//		sqlLengthExpression.append(")");
//
//		String temp = lengthString.toString();
//		if (temp.indexOf("(") > -1) {
//			temp = temp.substring(0, temp.indexOf("("));
//			return temp + sqlLengthExpression;
//		} else {
//			return temp;
//		}
		
//		String temp = getDataTypeName();
//		if (temp.indexOf("(") > -1) {
//			temp = temp.substring(0, temp.indexOf("("));
//		}
//		return temp+getLenExpression();
//	}
	
	public TypeEntry(DataType type,Integer length,Integer decimal,Platform platform,Platform targetPlatform){
		this.setType(type);
		this.setLength(length);
		this.setDecimal(decimal);
		this.setPlatform(platform);
		this.setTargetPlatform(targetPlatform);
	}
	
	/**
	 * 通过类型名称创建类型条目
	 * @param dataTypeName
	 * @param length
	 * @param decimal
	 * @param platform
	 *
	 * @author meichenhui
	 * @date 2011-9-17
	 *
	 */
	public TypeEntry(String dataTypeName,Integer length,Integer decimal,Platform platform,Platform targetPlatform){
		this.setLength(length);
		this.setDecimal(decimal);
		this.setPlatform(platform);
		this.setTargetPlatform(targetPlatform);
		
		processLenExpression(dataTypeName,length,decimal);
		
		setType(DataType.STRING); // 默认返回字符串类型
		for (int i = 0; i < DATATYPETABLE.length; i++) {
			String typeNameInTable = DATATYPETABLE[i][platform.getIndex()]; // 类型映射表中的描述
			String typeName = typeNameInTable; // 类型名称
//			if (typeNameInTable.contains("(")){ // 类型名称不带"(n)"的描述
//				typeName = typeNameInTable.substring(0,typeNameInTable.lastIndexOf('('));
//			}
			if (typeName.toLowerCase().equals(dataTypeName.toLowerCase())){ // 比较类型映射表的描述和传入的类型名称(忽略大小写)
				DataType coreType = DataType.values()[i]; // TYPETABLE当前位置对应的元类型
				// 校验数据长度和小数位数.必须符合DataType定义的值
				if (!validateLength(getLength(),coreType.getLength())){
					continue;
				}
				if (!validateLength(getDecimal(),coreType.getDecimal())){
					continue;
				}
				setType(coreType);
				break; // 取到正确的数据类型后结束循环
			}
		}
	}
	
	/**
	 * 通过类型名称创建类型条目<p/>
	 * 类型名描述是Number(10),Number(10,2)
	 * @param dataTypeName
	 * @param length
	 * @param decimal
	 * @param platform
	 *
	 * @author meichenhui
	 * @date 2011-9-18
	 *
	 */
	public TypeEntry(String dataTypeDesc,Platform platform,Platform targetPlatform){
		String[] splitedTypeDesc = spliteTypeLength(dataTypeDesc);
		this.setLength(splitedTypeDesc[1] == null ? null : Integer.valueOf(splitedTypeDesc[1]));
		this.setDecimal(splitedTypeDesc[2] == null ? null : Integer.valueOf(splitedTypeDesc[2]));
		this.setPlatform(platform);
		this.setTargetPlatform(targetPlatform);
		
		processLenExpression(dataTypeDesc);
		
		setType(DataType.STRING); // 默认返回字符串类型
		for (int i = 0; i < DATATYPETABLE.length; i++) {
			String typeNameInTable = DATATYPETABLE[i][platform.getIndex()]; // 类型映射表中的描述
			String typeName = typeNameInTable; // 类型名称
//			if (typeNameInTable.contains("(")){ // 类型名称不带"(n)"的描述
//				typeName = typeNameInTable.substring(0,typeNameInTable.lastIndexOf('('));
//			}
			if (typeName.toLowerCase().equals(splitedTypeDesc[0].toLowerCase())){ // 比较类型映射表的描述和传入的类型名称(忽略大小写)
				DataType coreType = DataType.values()[i]; // TYPETABLE当前位置对应的元类型
				// 校验数据长度和小数位数.必须符合DataType定义的值
				if (!validateLength(getLength(),coreType.getLength())){
					continue;
				}
				if (!validateLength(getDecimal(),coreType.getDecimal())){
					continue;
				}
				setType(coreType);
				break; // 取到正确的数据类型后结束循环
			}
		}
	}
	
	/**
	 * 把String(10)拆分成{"String","10"}<p/>
	 * 把Number(10,2)拆分成{"Number","10,2"}<p/>
	 * @return
	 *
	 * @author meichenhui
	 * @since 2011-9-18
	 *
	 */
	public static String[] spliteTypeLength(String typeDesc){
		int bracketIndex = typeDesc.lastIndexOf('(');
		if (bracketIndex < 0){
			return new String[]{typeDesc,null,null};
		}
		String typeName = typeDesc.substring(0,bracketIndex); // 类型名称
		String lengthDesc = typeDesc.substring(bracketIndex + 1,typeDesc.length() - 1);
		int commaIndex = lengthDesc.lastIndexOf(',');
		String length = commaIndex > 0 ? lengthDesc.substring(0,commaIndex) : lengthDesc;
		String decimal = commaIndex > 0 ? lengthDesc.substring(commaIndex + 1) : null;
		return new String[]{typeName,length,decimal};
	}
	
	/**
	 * 长度匹配
	 * DataType的定义
	 * null 	长度必须为空
	 * -1 		长度可以为任意非空值
	 * >-1		长度为指定值
	 * @param length
	 * @param dataType
	 * @return
	 *
	 * @author meichenhui
	 * @since 2011-9-17
	 *
	 */
	private boolean validateLength(Integer length,Integer dataTypeLength){
		if (dataTypeLength == null && length == null){
			return true;
		}
		if (length != null && dataTypeLength != null && dataTypeLength == -1){
			return true;
		}
		if (length != null && dataTypeLength != null && dataTypeLength > -1 && dataTypeLength.equals(length)){
			return true;
		}
		return false;
	}
	
	private void processLenExpression(String dataTypeName,Integer length,Integer decimal) {
		StringBuffer typeStr = new StringBuffer();
		typeStr.append(dataTypeName);
		typeStr.append("(");
		typeStr.append(length);
		typeStr.append(",");
		typeStr.append(decimal);
		typeStr.append(")");
		processLenExpression(typeStr.toString());
	}
	
	private void processLenExpression(String dataTypeDesc) {
		String[] splitedTypeDesc = spliteTypeLength(dataTypeDesc);
		StringBuffer lenExp = new StringBuffer();
		if (splitedTypeDesc[1] != null && splitedTypeDesc[1].length()>0 && Integer.valueOf(splitedTypeDesc[1]) > 0) {
			lenExp.append("(");
			lenExp.append(splitedTypeDesc[1]);
			if (splitedTypeDesc[2] != null && splitedTypeDesc[2].length()>0 &&Integer.valueOf(splitedTypeDesc[2]) > 0) {
				lenExp.append(",");
				lenExp.append(splitedTypeDesc[2]);
			}
			lenExp.append(")");
			this.setLenExpression(lenExp.toString());
		} else {
			this.setLenExpression("");
		}
	}

	public static void main(String[] args) {
		TypeEntry string = null;

		// // MODEL
//		System.out.println("-----MODEL-----");
//		string = new TypeEntry("string(100)", Platform.MODEL); // STRING
//		System.out.println(Platform.MODEL + ":" + string);
//		string = new TypeEntry("integer(10)", Platform.MODEL); // INT
//		System.out.println(Platform.MODEL + ":" + string);
//		string = new TypeEntry("boolean", Platform.MODEL); // BOOLEAN
//		System.out.println(Platform.MODEL + ":" + string);
//		string = new TypeEntry("decimal(100,2)", Platform.MODEL); // DECIMAL
//		System.out.println(Platform.MODEL + ":" + string);
//		string = new TypeEntry("date", Platform.MODEL); // DATE
//		System.out.println(Platform.MODEL + ":" + string);
//
//		// // ORACLE
//		System.out.println("-----ORACLE-----");
//		string = new TypeEntry("varchar(n)", 100, null, Platform.ERMASTER); // STRING
//		System.out.println(Platform.ERMASTER + ":" + string);
//		string = new TypeEntry("decimal(p)", 10, null, Platform.ERMASTER); // INT
//		System.out.println(Platform.ERMASTER + ":" + string);
//		string = new TypeEntry("char(1)", 1, null, Platform.ERMASTER); // BOOLEAN
//		System.out.println(Platform.ERMASTER + ":" + string);
//		string = new TypeEntry("decimal(p,s)", 100, 5, Platform.ERMASTER); // DECIMAL
//		System.out.println(Platform.ERMASTER + ":" + string);
//		string = new TypeEntry("timestamp", null, null, Platform.ERMASTER); // DATE
//		System.out.println(Platform.ERMASTER + ":" + string);
//
//		// // JAVA
//		System.out.println("-----JAVA-----");
//		string = new TypeEntry("String", 200, null, Platform.JAVA); // STRING
//		System.out.println(Platform.JAVA + ":" + string);
//		string = new TypeEntry("Long", 10, null, Platform.JAVA); // INT
//		System.out.println(Platform.JAVA + ":" + string);
//		string = new TypeEntry("Boolean", null, null, Platform.JAVA); // BOOLEAN
//		System.out.println(Platform.JAVA + ":" + string);
//		string = new TypeEntry("BigDecimal", 5, 5, Platform.JAVA); // DECIMAL
//		System.out.println(Platform.JAVA + ":" + string);
//		string = new TypeEntry("Date", null, null, Platform.JAVA); // DATE
//		System.out.println(Platform.JAVA + ":" + string);
//		//
//		// FLEX
//		System.out.println("-----FLEX-----");
//		string = new TypeEntry("String", 90, null, Platform.FLEX); // STRING
//		System.out.println(Platform.FLEX + ":" + string);
//		string = new TypeEntry("Number", 12, null, Platform.FLEX); // INT
//		System.out.println(Platform.FLEX + ":" + string);
//		string = new TypeEntry("Boolean", null, null, Platform.FLEX); // BOOLEAN
//		System.out.println(Platform.FLEX + ":" + string);
//		string = new TypeEntry("Number", 10, 0, Platform.FLEX); // DECIMAL
//		System.out.println(Platform.FLEX + ":" + string);
//		string = new TypeEntry("Date", null, null, Platform.FLEX); // DATE
//		System.out.println(Platform.FLEX + ":" + string);
//
//		// HIBERNATE_HBM
//		System.out.println("-----HIBERNATE_HBM-----");
//		string = new TypeEntry("String(50)", Platform.JAVA); // STRING
//		string.setPlatform(Platform.HIBERNATE_HBM);
//		System.out.println(Platform.HIBERNATE_HBM + ":" + string);
//
//		string = new TypeEntry("Long", Platform.JAVA); // INT
//		string.setPlatform(Platform.HIBERNATE_HBM);
//		System.out.println(Platform.HIBERNATE_HBM + ":" + string);
//
//		string = new TypeEntry("Boolean", Platform.JAVA); // BOOLEAN
//		string.setPlatform(Platform.HIBERNATE_HBM);
//		System.out.println(Platform.HIBERNATE_HBM + ":" + string);
//
//		string = new TypeEntry("BigDecimal(10,2)", Platform.JAVA); // DECIMAL
//		string.setPlatform(Platform.HIBERNATE_HBM);
//		System.out.println(Platform.HIBERNATE_HBM + ":" + string);
//
//		string = new TypeEntry("Date", Platform.JAVA); // DATE
//		string.setPlatform(Platform.HIBERNATE_HBM);
//		System.out.println(Platform.HIBERNATE_HBM + ":" + string);
//
//		// ERMASTER
//		System.out.println("-----ERMASTER-----");
//		string = new TypeEntry("String(50)", Platform.JAVA); // STRING
//		string.setPlatform(Platform.ERMASTER);
//		System.out.println(Platform.ERMASTER + ":" + string);
//
//		string = new TypeEntry("Long", Platform.JAVA); // INT
//		string.setPlatform(Platform.ERMASTER);
//		System.out.println(Platform.ERMASTER + ":" + string);
//
//		string = new TypeEntry("Boolean", Platform.JAVA); // BOOLEAN
//		string.setPlatform(Platform.ERMASTER);
//		System.out.println(Platform.ERMASTER + ":" + string);
//
//		string = new TypeEntry("BigDecimal(10,2)", Platform.JAVA); // DECIMAL
//		string.setPlatform(Platform.ERMASTER);
//		System.out.println(Platform.ERMASTER + ":" + string);
//
//		string = new TypeEntry("Date", Platform.JAVA); // DATE
//		string.setPlatform(Platform.ERMASTER);
//		System.out.println(Platform.ERMASTER + ":" + string);
//
//		// ORACLE
//		System.out.println("-----ORACLE-----");
//		string = new TypeEntry("String(50)", Platform.JAVA); // STRING
//		string.setPlatform(Platform.ORACLE);
//		System.out.println(Platform.ORACLE + ":" + string.toSQLString());
//
//		string = new TypeEntry("Long", Platform.JAVA); // INT
//		string.setPlatform(Platform.ORACLE);
//		System.out.println(Platform.ORACLE + ":" + string.toSQLString());
//
//		string = new TypeEntry("Boolean", Platform.JAVA); // BOOLEAN
//		string.setPlatform(Platform.ORACLE);
//		System.out.println(Platform.ORACLE + ":" + string.toSQLString());
//
//		string = new TypeEntry("BigDecimal(10,2)", Platform.JAVA); // DECIMAL
//		System.out.println("LenExpression : "+string.getLenExpression());
//		string.setPlatform(Platform.ORACLE);
//		System.out.println(Platform.ORACLE + ":" + string.toSQLString());
//
//		string = new TypeEntry("Date", Platform.JAVA); // DATE
//		System.out.println("LenExpression : "+string.getLenExpression());
//		string.setPlatform(Platform.ORACLE);
//		System.out.println(Platform.ORACLE + ":" + string.toSQLString());

		// String[] x = spliteTypeLength("Boolean");
		// String[] y = spliteTypeLength("Number(10,2)");
		// for(int i = 0;i < 3; i++){
		// System.out.println("X:" + x[i]);
		// System.out.println("Y:" + y[i]);
		// }
		// System.out.println(Integer.getInteger(null));
	}
}
